#ifndef _WEIGHTED_H_
#define _WEIGHTED_H_

template
<
    typename Criterion,
    typename NumericType
>
struct Weight : public Criterion
{
    NumericType weight;
};

template
<
    typename ... Criteria
>
struct Weighted;

template
<
    typename Criterion,
    typename ... Criteria
>
struct Weighted<Criterion, Criteria ... >
{
    template
    <
        typename SignalSystem,
        typename Map
    >
	bool operator()(const SignalSystem& system,
	             Map& oldResult, Map& newResult,
	             double oldTotal = 0, double newTotal = 0,
	             double totalWeight = 0)
	{
	    newResult.template set<Criterion>( criterion(system) * criterion.weight.value );
	    
	    oldTotal += oldResult.template get<Criterion>();
	    newTotal += newResult.template get<Criterion>();
	    totalWeight += criterion.weight.value;
	    //cout << criterion.getName() << ":  \t" << newResult.template get<Criterion>() << "  \t";
	    return weighted(system, oldResult, newResult, oldTotal, newTotal, totalWeight);
	}
	
protected:
    Weighted<Criteria ...> weighted;
    Criterion criterion;
};
	
template
<
>
struct Weighted<>
{
    template<
        typename SignalSystem,
        typename Map
    >
    bool operator()(
        const SignalSystem& system,
        Map& oldResult, Map& newResult,
        double oldTotal = 0, double newTotal = 0,
        double totalWeight = 0)
    {
        using namespace std;
        
        if ((newTotal > oldTotal) or ((oldTotal - newTotal) / oldTotal < 0.0001))
            return false;
        //cout << "*************************************************" << endl;
        
        cout << "\t" << newTotal / totalWeight
             << "\t" << (oldTotal - newTotal) / totalWeight << "\t" << endl;
        
        oldResult = newResult;
        return true;
    }
};

#endif // _WEIGHTED_H_
